﻿namespace DomainServices.Tools
{
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.IO;
    using System.Reflection;
    using System.Text;

    internal class ProjectSourceFileCache
    {
        private string _historyFilePath;
        private bool _isFileCacheCurrent;
        private ILogger _logger;
        private ProjectFileReader _projectFileReader;
        private string _rootProjectPath;
        private Dictionary<string, IEnumerable<string>> _sourceFilesByProject;

        internal ProjectSourceFileCache(string rootProjectPath, string historyFilePath, ILogger logger, ProjectFileReader projectFileReader)
        {
            if (string.IsNullOrEmpty(rootProjectPath))
            {
                throw new ArgumentNullException("rootProjectPath");
            }
            if (string.IsNullOrEmpty(historyFilePath))
            {
                throw new ArgumentNullException("historyFilePath");
            }
            if (logger == null)
            {
                throw new ArgumentNullException("logger");
            }
            if (projectFileReader == null)
            {
                throw new ArgumentNullException("projectFileReader");
            }
            this._rootProjectPath = rootProjectPath;
            this._historyFilePath = historyFilePath;
            this._projectFileReader = projectFileReader;
            this._logger = logger;
        }

        internal IEnumerable<string> GetAllKnownProjects()
        {
            return this.GetOrLoadSourceFilesByProject().Keys;
        }

        internal Dictionary<string, IEnumerable<string>> GetOrLoadSourceFilesByProject()
        {
            if ((this.SourceFilesByProject.Count == 0) && !this.LoadCacheFromFile())
            {
                this.LoadSourceFilesFromProjects();
            }
            return this.SourceFilesByProject;
        }

        internal IEnumerable<string> GetSourceFilesInAllProjects()
        {
            List<string> list = new List<string>();
            foreach (string str in this.GetAllKnownProjects())
            {
                list.AddRange(this.GetSourceFilesInProject(str));
            }
            return list;
        }

        internal IEnumerable<string> GetSourceFilesInProject(string projectPath)
        {
            if (string.IsNullOrEmpty(projectPath))
            {
                throw new ArgumentNullException("projectPath");
            }
            IEnumerable<string> enumerable = null;
            this.GetOrLoadSourceFilesByProject().TryGetValue(projectPath, out enumerable);
            return enumerable;
        }

        internal bool LoadCacheFromFile()
        {
            this.IsFileCacheCurrent = false;
            if (!File.Exists(this._historyFilePath))
            {
                return false;
            }
            DateTime lastWriteTime = File.GetLastWriteTime(this._rootProjectPath);
            DateTime time2 = File.GetLastWriteTime(this._historyFilePath);
            if (lastWriteTime.CompareTo(time2) > 0)
            {
                return false;
            }
            foreach (string str2 in File.ReadAllText(this._historyFilePath).Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries))
            {
                string[] strArray2 = str2.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                if (strArray2.Length < 2)
                {
                    this.SourceFilesByProject.Clear();
                    return false;
                }
                string path = strArray2[0];
                if (File.Exists(path))
                {
                    List<string> list = new List<string>();
                    if (strArray2.Length >= 3)
                    {
                        lastWriteTime = File.GetLastWriteTime(path);
                        long result = 0L;
                        if (!long.TryParse(strArray2[1], out result) || (lastWriteTime.Ticks > result))
                        {
                            list.AddRange(this._projectFileReader.LoadSourceFilesFromProject(path));
                        }
                        else
                        {
                            for (int i = 2; i < strArray2.Length; i++)
                            {
                                string str4 = strArray2[i];
                                if (!string.IsNullOrEmpty(str4))
                                {
                                    string str5 = ProjectFileReader.ConvertToFullPath(str4, path);
                                    if (File.Exists(str5))
                                    {
                                        list.Add(str5);
                                    }
                                }
                            }
                        }
                    }
                    this[path] = list;
                }
            }
            this.IsFileCacheCurrent = true;
            return true;
        }

        internal void LoadSourceFilesFromProjects()
        {
            this.IsFileCacheCurrent = false;
            IEnumerable<string> enumerable = this._projectFileReader.LoadProjectReferences(this._rootProjectPath);
            this[this._rootProjectPath] = this._projectFileReader.LoadSourceFilesFromProject(this._rootProjectPath);
            foreach (string str in enumerable)
            {
                IEnumerable<string> enumerable2 = this._projectFileReader.LoadSourceFilesFromProject(str);
                this[str] = enumerable2;
            }
        }

        internal bool SaveCacheToFile()
        {
            if (this._sourceFilesByProject == null)
            {
                return false;
            }
            StringBuilder builder = new StringBuilder();
            foreach (string str in this.SourceFilesByProject.Keys)
            {
                StringBuilder builder2 = new StringBuilder();
                builder2.Append(str);
                builder2.Append(',');
                builder2.Append(File.GetLastWriteTime(str).Ticks.ToString(CultureInfo.InvariantCulture));
                builder2.Append(',');
                foreach (string str2 in this.SourceFilesByProject[str])
                {
                    string str3 = ProjectFileReader.ConvertToRelativePath(str2, str);
                    builder2.Append(str3);
                    builder2.Append(',');
                }
                builder.AppendLine(builder2.ToString());
            }
            Exception exception = null;
            try
            {
                File.WriteAllText(this._historyFilePath, builder.ToString());
            }
            catch (IOException exception2)
            {
                exception = exception2;
            }
            catch (UnauthorizedAccessException exception3)
            {
                exception = exception3;
            }
            if (exception != null)
            {
                this._logger.LogWarning(string.Format(CultureInfo.CurrentCulture, Resource.Failed_To_Write_File, new object[] { this._historyFilePath, exception.Message }));
                return false;
            }
            this.IsFileCacheCurrent = true;
            return true;
        }

        internal bool IsFileCacheCurrent
        {
            get
            {
                return this._isFileCacheCurrent;
            }
            private set
            {
                this._isFileCacheCurrent = value;
            }
        }

        internal IEnumerable<string> this[string projectPath]
        {
            get
            {
                if (string.IsNullOrEmpty(projectPath))
                {
                    throw new ArgumentNullException("projectPath");
                }
                IEnumerable<string> enumerable = null;
                this.SourceFilesByProject.TryGetValue(projectPath, out enumerable);
                return enumerable;
            }
            set
            {
                if (string.IsNullOrEmpty(projectPath))
                {
                    throw new ArgumentNullException("projectPath");
                }
                this.IsFileCacheCurrent = false;
                this.SourceFilesByProject[projectPath] = value;
            }
        }

        internal Dictionary<string, IEnumerable<string>> SourceFilesByProject
        {
            get
            {
                if (this._sourceFilesByProject == null)
                {
                    this._sourceFilesByProject = new Dictionary<string, IEnumerable<string>>(StringComparer.OrdinalIgnoreCase);
                }
                return this._sourceFilesByProject;
            }
        }
    }
}

